package cn.com.heaton.bleLib.logic;

import android.bluetooth.BluetoothGattCharacteristic;
import android.os.Handler;
import android.os.Message;

import java.sql.Time;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import cn.com.heaton.bleLib.R;
import cn.com.heaton.bleLib.ble.Ble;
import cn.com.heaton.bleLib.ble.BleHandler;
import cn.com.heaton.bleLib.ble.L;
import cn.com.heaton.bleLib.ble.callback.BleChaChangeCallback;
import cn.com.heaton.bleLib.ble.callback.BleWriteCallback;
import cn.com.heaton.bleLib.ble.model.BleDevice;
import cn.com.heaton.bleLib.logic.bean.BlackBean;
import cn.com.heaton.bleLib.logic.bean.DeviceInfo;
import cn.com.heaton.bleLib.logic.bean.RecordBean;
import cn.com.heaton.bleLib.logic.bean.TimeBean;
import cn.com.heaton.bleLib.logic.bean.WhiteBean;
import cn.com.heaton.bleLib.logic.command.BleCommandQueue;
import cn.com.heaton.bleLib.logic.command.Command;
import cn.com.heaton.bleLib.logic.command.CommandQueue;
import cn.com.heaton.bleLib.logic.command.impl.AuthKeyRequest;
import cn.com.heaton.bleLib.logic.command.impl.AuthRequest;
import cn.com.heaton.bleLib.logic.command.impl.CmdDeviceBlack;
import cn.com.heaton.bleLib.logic.command.impl.CmdDeviceInfoFetch;
import cn.com.heaton.bleLib.logic.command.impl.CmdDeviceRecord;
import cn.com.heaton.bleLib.logic.command.impl.CmdDeviceWhite;
import cn.com.heaton.bleLib.logic.command.impl.CmdFetchTime;
import cn.com.heaton.bleLib.logic.command.impl.CmdFetchVersion;
import cn.com.heaton.bleLib.logic.command.impl.CmdInterfaceSet;
import cn.com.heaton.bleLib.logic.command.impl.CmdRequestOpenDoor;
import cn.com.heaton.bleLib.logic.command.impl.CmdSyncTime;
import cn.com.heaton.bleLib.logic.notify.AuthCallBack;
import cn.com.heaton.bleLib.logic.notify.CommonCallBack;
import cn.com.heaton.bleLib.logic.notify.DeviceInfoCallBack;
import cn.com.heaton.bleLib.logic.notify.FetchTimeCallBack;
import cn.com.heaton.bleLib.logic.notify.OnBlackCallBack;
import cn.com.heaton.bleLib.logic.notify.OnRecordCallBack;
import cn.com.heaton.bleLib.logic.notify.OnWhiteCallBack;
import cn.com.heaton.bleLib.logic.notify.OpenDoorCallBack;

import static cn.com.heaton.bleLib.logic.command.Command.FRAME_HEADER_CODE;


/**
 * 蓝牙模块逻辑处理
 * Created by bryan on 2019/5/21.
 */
public class ZhyBleLogicManager {

    public static final String TAG = "ZhyBleLogicManager";

    //指令超时时间
    public long OverTime = 5000;


    byte[] key = new byte[]{(byte) 0xfa, 0x02, 0x61, 0x00, 0x65, 0x35, 0x18, 0x01, (byte) 0xFA, 0x02, 0x61, 0x00, 0x65, 0x35, 0x18, 0x01, (byte) 0xFA, 0x02, 0x61, 0x00, 0x65, 0x35, 0x18, 0x01};


    private CommandQueue mCmdQueue;
    private Ble mBle;
    /*
     * 标识设备上一次操作的数据，过滤重复返回的数据，String是设备的MAC地址
     * 设备上一次写入或者读到的数据，都会在这边进行缓存
     */
    private HashMap<String, byte[]> mLastOperationValueMap = new HashMap<>();
    /*
     * 收到的临时的值， key是Mac,
     * Object中的Integer表示应该收到的目标长度(数据长度，不包含帧头)，Value表示当前收到的值，目前只有一个，先这样设计,一个设备只允许有一个临时的值
     * */
    private HashMap<String, byte[]> mLTempRevBufferMap = new HashMap<>();


    /*开门回调监听*/
    private OpenDoorCallBack openDoorCallBack = null;
    //设备授权回调监听
    private AuthCallBack authCallBack = null;
    //获取设备时间回调监听
    private FetchTimeCallBack fetchTimeCallBack = null;
    //同步系统时间给设备
    private CommonCallBack syncTimeCallBack = null;

    //获取设备版本号
    private CommonCallBack versionCallBack = null;


    //设置内置外置的接口
    private CommonCallBack loraSetCallBack = null;

    //获取设备信息接口
    private DeviceInfoCallBack deviceInfoCallBack = null;
    //开门记录回调
    private OnRecordCallBack recordCallBack = null;
    //白名单回调
    private OnWhiteCallBack whiteCallBack = null;
    //黑名单回调
    private OnBlackCallBack blackCallBack = null;


    private static final int Msg_Auth = 0x01;
    private static final int Msg_Open_Door = 0x02;
    private static final int Msg_Fetch_Time = 0x03;
    private static final int Msg_Sync_Time = 0x04;
    private static final int Msg_Version = 0x05;
    private static final int Msg_Lora_Model = 0x06;
    private static final int Msg_Device_Info = 0x07;
    private static final int Msg_Record = 0x08;
    private static final int Msg_White = 0x09;
    private static final int Msg_Black = 0x0a;


    //用于处理指令超时
    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case Msg_Auth:
                    if (authCallBack != null) {
                        authCallBack.authFail();
                    }
                    break;
                case Msg_Open_Door:
                    if (openDoorCallBack != null) {
                        openDoorCallBack.openFail((byte) 0x04);
                    }
                    break;
                case Msg_Fetch_Time:
                    if (fetchTimeCallBack != null) {
                        fetchTimeCallBack.onFail("指令超时");
                    }
                    break;
                case Msg_Sync_Time:
                    if (syncTimeCallBack != null) {
                        syncTimeCallBack.onFail("指令超时");
                    }
                    break;
                case Msg_Version:
                    if (versionCallBack != null) {
                        versionCallBack.onFail("指令超时");
                    }
                    break;
                case Msg_Lora_Model:
                    if (loraSetCallBack != null) {
                        loraSetCallBack.onFail("指令超时");
                    }
                    break;
                case Msg_Device_Info:
                    if (deviceInfoCallBack != null) {
                        deviceInfoCallBack.onFail("指令超时");
                    }

                    break;
                case Msg_Record:
                    if (recordCallBack != null) {
                        recordCallBack.onFail("指令超时");
                    }
                    break;
                case Msg_White:
                    if (whiteCallBack != null) {
                        whiteCallBack.onFail("指令超时");
                    }

                    break;
                case Msg_Black:
                    if (blackCallBack != null) {
                        blackCallBack.onFail("指令超时");
                    }
                    break;
            }
            return false;
        }
    });


    public ZhyBleLogicManager(Ble mBle, Ble.Options opts) {
        this.mBle = mBle;
        mCmdQueue = new BleCommandQueue();
        this.mBle.addChaChangeListener(callback);
        OverTime = opts.getCmdOverTime();
    }

    /**
     * 特征值变化注入到变化的监听中，所有的操作都在这边统一处理
     */
    private BleChaChangeCallback callback = new BleChaChangeCallback() {
        @Override
        public void onChanged(Object device, byte[] oriValue) {
            //拷贝一份数据，防止直接修改了特征值里面写过来的数据，影响其他地方的使用
            byte[] value = new byte[oriValue.length];
            System.arraycopy(oriValue, 0, value, 0, oriValue.length);
            L.i(TAG, "收到消息：" + HexUtil.encodeHexStr(value));
            readChaNotifyValue((BleDevice) device, value);
        }
    };

    /**
     * 获取特征值变化的值
     *
     * @param device
     * @param receiverBuffer
     */
    private void readChaNotifyValue(BleDevice device, byte[] receiverBuffer) {
        try {
            byte[] lastOperationValue = mLastOperationValueMap.get(device.getBleAddress());
            //主要是为了要过滤在开发过程中可能会碰到的多次返回同一条数据的问题
            if (receiverBuffer != lastOperationValue) {
                //
                mLastOperationValueMap.put(device.getBleAddress(), receiverBuffer);
                if (hasFrameCode(receiverBuffer)) {
                    mLTempRevBufferMap.remove(device.getBleAddress());//移除掉之前的旧数据

                    //判断是不是需要的数据
                    //帧头，跟数据长度是不参与加密的，先读出是否是完整的数据
                    int dataLen = receiverBuffer[2];//数据包长度（不包含FrameCode）
                    int allLength = dataLen + 2;//完整数据包的总长度
                    if (allLength > receiverBuffer.length) {
                        //表示应该收到的数据包大于当前收到的数据，会分包发送过来
                        L.i(TAG, "数据过大，分包发送,当前数据：" + HexUtil.encodeHexStr(receiverBuffer));
                        //缓存的数据，数据长度为总长度，但是只有前面赋值了，后面是没有值的，最后会通过数据校验判断是不是需要的值
                        byte[] tempByte = new byte[allLength];
                        //拷贝赋值到前面的字节中
                        System.arraycopy(receiverBuffer, 0, tempByte, 0, receiverBuffer.length);
                        mLTempRevBufferMap.put(device.getBleAddress(), tempByte);
                    } else {
                        //表示接收到完整的数据
                        L.i(TAG, "接收到了完整的数据--->" + HexUtil.encodeHexStr(receiverBuffer) + " ---   开始做数据解密  ");
                        //数据解密
                        byte[] tempBuffer = new byte[receiverBuffer.length - 3];
                        //把需要解密的数据拷贝到tempBuffer，然后再调用解密算法
                        System.arraycopy(receiverBuffer, 3, tempBuffer, 0, tempBuffer.length);
                        //解密获取到原始的数据
                        byte[] oriData = Rc4.RC4Base(tempBuffer, Rc4.RC4Key);
                        //组装数据，得到完整的数据
                        System.arraycopy(oriData, 0, receiverBuffer, 3, oriData.length);
                        L.i(TAG, "解密后的数据：" + HexUtil.encodeHexStr(receiverBuffer));
                        // dataLen - 3 为实际有用的数据长度，dataLen包含了数据长度，校验和，帧编号3个长度
                        byte[] usefulData = new byte[dataLen - 3];
                        //从第5个位置开始做拷贝（前面5个都是没用的数据校验位）
                        System.arraycopy(receiverBuffer, 5, usefulData, 0, usefulData.length);
                        handleReceiveData(device, usefulData);
                    }
                } else {
                    //没有枕头的数据
                    byte[] lastReadValue = mLTempRevBufferMap.get(device.getBleAddress());
                    if (lastReadValue != null) {
                        //说明有缓存的数据，将新接受到的值存放进去，通过数据校验来判断是不是需要的数据
                        //1-拷贝数组，避免修改到缓存的数据，导致以后的其他数据比较出错
                        byte[] lastValue = new byte[lastReadValue.length];
                        System.arraycopy(lastReadValue, 0, lastValue, 0, lastReadValue.length);
                        //2-再次拷贝新接收的数据，防止影响后面的判断，
                        byte[] copyData = new byte[receiverBuffer.length];
                        System.arraycopy(receiverBuffer, 0, copyData, 0, copyData.length);


                        //3- 将新接到的数据拼接到旧的数据
                        int length = copyData.length;
                        int startLength = lastValue.length - length;//从哪里开始拷贝
                        System.arraycopy(copyData, 0, lastValue, startLength, length);

                        //4-做数据解密
                        // lastvalue 是目前收到的完整的数据了。
                        L.i(TAG, "解密前数据：" + HexUtil.encodeHexStr(lastValue));
                        byte[] tempBuffer = new byte[lastValue.length - 3];
                        //把需要解密的数据拷贝到tempBuffer，然后再调用解密算法
                        System.arraycopy(lastValue, 3, tempBuffer, 0, tempBuffer.length);
                        //解密获取到原始的数据
                        byte[] oriData = Rc4.RC4Base(tempBuffer, Rc4.RC4Key);
                        //组装数据，得到完整的数据
                        System.arraycopy(oriData, 0, lastValue, 3, oriData.length);
                        L.i(TAG, "解密后的数据：" + HexUtil.encodeHexStr(lastValue));

                        //5-进行数据校验，校验接收到的数据是不是上一个数据里需要的数据
                        byte check = 0;
                        check += lastValue[2];
                        for (int i = 4; i < lastValue.length; i++) {
                            check += lastValue[i];
                        }
                        L.i(TAG, "校验和：" + HexUtil.Byte2Hex(lastValue[3]));
                        L.i(TAG, "算出来的校验和：" + HexUtil.Byte2Hex((byte) -check));


                        if (lastValue[3] + check == 0) {
                            L.i(TAG, "分包数据校验通过,数据为" + HexUtil.encodeHexStr(lastValue));
                            byte[] usefulData = new byte[lastValue.length - 5];
                            //从第个位置开始做拷贝（前面5个都是没用的数据校验位）
                            System.arraycopy(lastValue, 5, usefulData, 0, usefulData.length);
                            handleReceiveData(device, usefulData);
                            return;
                        } else {
                            L.i(TAG, "未通过数据校验，继续往下跑");
                        }
                    }
                    if (receiverBuffer.length == 8) {
                        //请求授权返回的信息，需要对这8个字节进行3des加密，然后在发送给设备
                        L.i("bryan", "3DES加密前>>>: " + HexUtil.encodeHexStr(receiverBuffer));
                        byte[] resultEncyByte = DES3Utils.encryptMode(key, receiverBuffer);
                        if (resultEncyByte != null) {
                            mHandler.removeMessages(Msg_Auth);
                            L.i("bryan", "3DES加密后>>>: " + HexUtil.encodeHexStr(resultEncyByte));
                            authResponeCmd(device, resultEncyByte);

                        }
                    } else {
                        L.i(TAG, "没有获取到缓存的数据");
                    }
                }
            } else {
                L.i(TAG, "数据一样，抛弃 ： " + HexUtil.encodeHexStr(receiverBuffer));
            }
        } catch (Exception e) {
            L.i(TAG, "解析数据发生异常" + e.getMessage());
        }
    }

    private void handleReceiveData(final BleDevice device, byte[] data) {
        try {
            L.i(TAG, "处理返回的数据：" + HexUtil.encodeHexStr(data));
            int offset = 0;
            byte cmd = data[0];
            offset += 1;
            //Integer.parseInt(Integer.toString(cmd & 0xff))
            switch (cmd) {
                case Command.Cmd_Open_Door_In:
                    L.i(TAG, "开门回馈");
                    if (data.length == 2) {
                        mHandler.removeMessages(Msg_Open_Door);
                        handleOpenDoorCallBack(data, offset);
                    }
                    break;
                case Command.Cmd_Fetch_Time://获取设备时间
                    if (data.length == 8) {
                        mHandler.removeMessages(Msg_Fetch_Time);
                        TimeBean timeBean = TimeBean.parseTimeBean(data, offset);
                        if (fetchTimeCallBack != null) {
                            fetchTimeCallBack.onSuccess(timeBean);
                            fetchTimeCallBack = null;
                        }
                    }
                    break;
                case Command.Cmd_Lora_In_Out:
                    L.i(TAG, "内外置");
                    if (data.length == 2) {
                        mHandler.removeMessages(Msg_Lora_Model);
                        handleLoraSetCallBack(data, offset);
                    }
                    break;
                case Command.Cmd_Fetch_Device_Info:
                    L.i(TAG, "获取设备信息");
                    if (data.length > 1) {
                        mHandler.removeMessages(Msg_Device_Info);

                        DeviceInfo deviceInfo = DeviceInfo.of(data, offset);
                        if (deviceInfoCallBack != null) {
                            deviceInfoCallBack.onSuccess(deviceInfo);
                            deviceInfoCallBack = null;
                        }
                    }
                    break;
                case Command.Cmd_Read_Record:
                    L.i(TAG, "获取开门记录");
                    if (data.length > 5) {
                        mHandler.removeMessages(Msg_Record);
                        RecordBean recordBean = RecordBean.of(data, offset);
                        if (recordCallBack != null) {
                            recordCallBack.onSuccess(recordBean);
                            recordCallBack = null;
                        }
                    }
                    break;
                case Command.Cmd_Read_White:
                    L.i(TAG, "获取白名单记录");
                    if (data.length > 5) {
                        mHandler.removeMessages(Msg_White);

                        WhiteBean whiteBean = WhiteBean.of(data, offset);
                        if (whiteCallBack != null) {
                            whiteCallBack.onSuccess(whiteBean);
                            whiteCallBack = null;
                        }
                    }
                    break;
                case Command.Cmd_Read_Black:
                    L.i(TAG, "获取黑名单记录");
                    if (data.length > 5) {
                        mHandler.removeMessages(Msg_Black);

                        BlackBean blackBean = BlackBean.of(data, offset);
                        if (blackCallBack != null) {
                            blackCallBack.onSuccess(blackBean);
                            blackCallBack = null;
                        }
                    }
                    break;

                case Command.Cmd_Read_Version:
                    L.i(TAG, "获取设备版本号");
                    if (data.length == 6) {
                        mHandler.removeMessages(Msg_Version);

                        byte one = data[offset];
                        offset++;
                        byte two = data[offset];
                        offset++;
                        byte three = data[offset];
                        offset++;
                        byte four = data[offset];
                        offset++;
                        byte five = data[offset];
                        offset++;
                        String version = "v"
                                + Integer.parseInt(HexUtil.Byte2Hex(one), 16)
                                + '.'
                                + Integer.parseInt(HexUtil.Byte2Hex(two), 16)
                                + '.'
                                + Integer.parseInt(HexUtil.Byte2Hex(three), 16)
                                + '.'
                                + Integer.parseInt(HexUtil.Byte2Hex(four), 16)
                                + '.'
                                + Integer.parseInt(HexUtil.Byte2Hex(five), 16);
                        if (versionCallBack != null) {
                            versionCallBack.onSuccess(version);
                            versionCallBack = null;
                        }
                    }
                    break;
                case Command.Cmd_Set_Time:
                    if (data.length == 2) {
                        mHandler.removeMessages(Msg_Sync_Time);
                        handleSyncTimeCallBack(data, offset);
                    }
                    break;
                default:
                    L.i(TAG, "未能识别的指令类型");
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    /**
     * 处理开门结果
     *
     * @param data
     */
    private void handleOpenDoorCallBack(byte[] data, int offset) {

        if (data[offset] == 0x00) {
            if (openDoorCallBack != null) {
                openDoorCallBack.openSuccess();
            }
        } else {
            //开门失败，把code返回回去
            if (openDoorCallBack != null) {
                openDoorCallBack.openFail(data[offset]);
            }
        }
        openDoorCallBack = null;
    }

    /**
     * 处理开门结果
     *
     * @param data
     */
    private void handleSyncTimeCallBack(byte[] data, int offset) {
        if (data[offset] == 0x00) {
            if (syncTimeCallBack != null) {
                syncTimeCallBack.onSuccess("成功");
            }
        } else {
            //开门失败，把code返回回去
            if (syncTimeCallBack != null) {
                syncTimeCallBack.onFail("" + data[offset]);
            }
        }
        openDoorCallBack = null;
    }

    /**
     * 处理lara设置结果
     *
     * @param data
     * @param offset
     */
    private void handleLoraSetCallBack(byte[] data, int offset) {
        if (data[offset] == 0x00) {
            if (loraSetCallBack != null) {
                loraSetCallBack.onSuccess("设置成功");
            }
        } else {
            if (loraSetCallBack != null) {
                loraSetCallBack.onFail("" + data[offset]);
            }
        }
        loraSetCallBack = null;
    }

    /**
     * 当设备连接成功，要初始化一些数据，防止异常情况
     *
     * @param device
     */
    public void onDeviceConnected(BleDevice device) {
        mLastOperationValueMap.remove(device.getBleAddress());
        mLTempRevBufferMap.remove(device.getBleAddress());
    }

    /**
     * 请求设备认证
     *
     * @param bleDevice
     * @param authCallBack
     */
    public void authDevice(BleDevice bleDevice, AuthCallBack authCallBack) {
        this.authCallBack = authCallBack;
        AuthRequest cmd = new AuthRequest(mBle, bleDevice, mWriteCallBack);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Auth);
        mHandler.sendEmptyMessageDelayed(Msg_Auth, OverTime);
    }

    /**
     * 授权密钥应答串
     */
    public void authResponeCmd(BleDevice bleDevice, byte[] data) {
        if (authCallBack != null) {
            BleHandler.of().postDelayed(new Runnable() {
                @Override
                public void run() {
                    authCallBack.authSuccess();
                    authCallBack = null;
                }
            }, 1000);
        }
        AuthKeyRequest cmd = new AuthKeyRequest(mBle, bleDevice, mWriteCallBack, data);
        mCmdQueue.add(cmd);
    }

    /**
     * 获取时间
     *
     * @param bleDevice
     * @param callBack
     */
    public void requestFetchTime(BleDevice bleDevice, FetchTimeCallBack callBack) {
        this.fetchTimeCallBack = callBack;
        CmdFetchTime cmd = new CmdFetchTime(mBle, bleDevice, mWriteCallBack);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Fetch_Time);
        mHandler.sendEmptyMessageDelayed(Msg_Fetch_Time, OverTime);


    }

    /**
     * 同步系统时间给设备
     *
     * @param bleDevice
     * @param callBack
     */
    public void requestSycnTime(BleDevice bleDevice, CommonCallBack callBack) {
        this.syncTimeCallBack = callBack;
        CmdSyncTime cmd = new CmdSyncTime(mBle, bleDevice, mWriteCallBack);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Sync_Time);
        mHandler.sendEmptyMessageDelayed(Msg_Sync_Time, OverTime);

    }

    /**
     * 请求模块的版本号
     *
     * @param bleDevice
     * @param callBack
     */
    public void requestVersion(BleDevice bleDevice, CommonCallBack callBack) {
        this.versionCallBack = callBack;
        CmdFetchVersion cmd = new CmdFetchVersion(mBle, bleDevice, mWriteCallBack);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Version);
        mHandler.sendEmptyMessageDelayed(Msg_Version, OverTime);

    }

    /**
     * 设置内置外置的接口
     *
     * @param device
     * @param isInModel 是否是内置模式
     * @param isATModel 是否是AT模式
     * @param callBack
     */
    public void setInterface(BleDevice device, boolean isInModel, boolean isATModel, CommonCallBack callBack) {
        this.loraSetCallBack = callBack;
        CmdInterfaceSet cmd = new CmdInterfaceSet(mBle, device, mWriteCallBack, isInModel, isATModel);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Lora_Model);
        mHandler.sendEmptyMessageDelayed(Msg_Lora_Model, OverTime);

    }

    /**
     * 获取设备信息
     *
     * @param device
     * @param callBack
     */
    public void getDeviceInfo(BleDevice device, DeviceInfoCallBack callBack) {
        this.deviceInfoCallBack = callBack;
        CmdDeviceInfoFetch cmd = new CmdDeviceInfoFetch(mBle, device, mWriteCallBack);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Device_Info);
        mHandler.sendEmptyMessageDelayed(Msg_Device_Info, OverTime);

    }

    /**
     * 获取开门记录
     *
     * @param device
     * @param index
     * @param callBack
     */
    public void getRecord(BleDevice device, int index, OnRecordCallBack callBack) {
        this.recordCallBack = callBack;
        CmdDeviceRecord cmd = new CmdDeviceRecord(mBle, device, mWriteCallBack, index);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Record);
        mHandler.sendEmptyMessageDelayed(Msg_Record, OverTime);

    }

    /**
     * 获取白名单记录
     *
     * @param device
     * @param index
     * @param callBack
     */
    public void getWhite(BleDevice device, int index, OnWhiteCallBack callBack) {
        this.whiteCallBack = callBack;
        CmdDeviceWhite cmd = new CmdDeviceWhite(mBle, device, mWriteCallBack, index);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_White);
        mHandler.sendEmptyMessageDelayed(Msg_White, OverTime);

    }

    /**
     * 获取黑名单记录
     *
     * @param device
     * @param index
     * @param callBack
     */
    public void getBlack(BleDevice device, int index, OnBlackCallBack callBack) {
        this.blackCallBack = callBack;
        CmdDeviceBlack cmd = new CmdDeviceBlack(mBle, device, mWriteCallBack, index);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Black);
        mHandler.sendEmptyMessageDelayed(Msg_Black, OverTime);

    }


    /**
     * 施工开门
     *
     * @param bleDevice
     * @param openDoorCallBack
     */
    public void requestOpenDoor(BleDevice bleDevice, OpenDoorCallBack openDoorCallBack) {
        this.openDoorCallBack = openDoorCallBack;
        CmdRequestOpenDoor cmd = new CmdRequestOpenDoor(mBle, bleDevice, mWriteCallBack, openDoorCallBack);
        mCmdQueue.add(cmd);
        mHandler.removeMessages(Msg_Open_Door);
        mHandler.sendEmptyMessageDelayed(Msg_Open_Door, OverTime);
    }


    /**
     * 写入数据监听
     */
    private BleWriteCallback mWriteCallBack = new BleWriteCallback() {
        @Override
        public void onWriteSuccess(BluetoothGattCharacteristic characteristic) {
            mCmdQueue.next();
        }
    };

    /**
     * 校验校验头
     *
     * @param data
     * @return
     */
    private boolean hasFrameCode(byte[] data) {
        if (data[0] == FRAME_HEADER_CODE[0] && data[1] == FRAME_HEADER_CODE[1]) {
            return true;
        }
        return false;
    }


}
